package com.googlecode.android_di;

import static java.lang.String.format;

import java.lang.reflect.Field;

import roboguice.inject.ContentView;
import roboguice.inject.InjectResource;
import roboguice.inject.InjectView;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

public class SimpleRoboguice {
    private static void injectViewAndResource(Activity anObject) {
        // the reflection API requires that each class in the hierarchy be considered
        // start with the lowest class in the hierarchy
        // until the top is reached
        for (Class<?> clz = anObject.getClass(); clz != null && !Activity.class.equals(clz); clz = clz.getSuperclass()) {
            // inject the dependencies for this class
            injectAndroidForSingleClass(anObject, clz);
        }
    }

    private static void injectAndroidForSingleClass(Activity anObject, Class<?> aClass) {
        // for each
        for (Field field : aClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(InjectView.class)) {
                field.setAccessible(true);
                try {
                    // if the field has not already been set (possibly through injection)...
                    if (field.get(anObject) == null) {
                        InjectView iv = field.getAnnotation(InjectView.class);
                        final Object injectedValue = anObject.findViewById(iv.value());
                        field.set(anObject, injectedValue);
                    }
                } catch (IllegalArgumentException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(format("Unable to access field %s.", field.getName()), e);
                }
            } else if (field.isAnnotationPresent(InjectResource.class)) {
                field.setAccessible(true);
                try {
                    // if the field has not already been set (possibly through injection)...
                    if (field.get(anObject) == null) {
                        InjectResource iv = field.getAnnotation(InjectResource.class);
                        final int id = iv.value();
                        final Class<?> t = field.getType();
                        final Resources resources = anObject.getApplication().getResources();
                        Object value = null;
                        if (String.class.isAssignableFrom(t)) {
                            value = resources.getString(id);
                        } else if (boolean.class.isAssignableFrom(t) || Boolean.class.isAssignableFrom(t)) {
                            value = resources.getBoolean(id);
                        } else if (ColorStateList.class.isAssignableFrom(t)) {
                            value = resources.getColorStateList(id);
                        } else if (int.class.isAssignableFrom(t) || Integer.class.isAssignableFrom(t)) {
                            value = resources.getInteger(id);
                        } else if (Drawable.class.isAssignableFrom(t)) {
                            value = resources.getDrawable(id);
                        } else if (String[].class.isAssignableFrom(t)) {
                            value = resources.getStringArray(id);
                        } else if (int[].class.isAssignableFrom(t) || Integer[].class.isAssignableFrom(t)) {
                            value = resources.getIntArray(id);
                        } else if (Animation.class.isAssignableFrom(t)) {
                            value = AnimationUtils.loadAnimation(anObject, id);
                        } else if (Movie.class.isAssignableFrom(t)) {
                            value = resources.getMovie(id);
                        }
                        field.set(anObject, value);
                    }
                } catch (IllegalArgumentException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(format("Unable to access field %s.", field.getName()), e);
                }
            }
        }
    }

    public static void injectActivity(Activity anObject) {
        for (Class<?> clz = anObject.getClass(); clz != null && !Activity.class.equals(clz); clz = clz.getSuperclass()) {
            ContentView cv = clz.getAnnotation(ContentView.class);
            if (cv != null) {
                anObject.setContentView(cv.value());
                break;
            }
        }
        injectViewAndResource(anObject);
    }
}
